import os
import re
import time
import requests
from collections import defaultdict

def sanitize_filename(name):
    """移除文件名中的非法字符并限制长度"""
    return re.sub(r'[\\/*?:"<>|]', '_', str(name))[:120]

def fetch_song_list():
    """获取所有歌曲元数据列表"""
    api_url = "https://monster-siren.hypergryph.com/api/songs"
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
    try:
        response = requests.get(api_url, headers=headers, timeout=15)
        response.raise_for_status()
        return response.json()["data"]["list"]
    except Exception as e:
        print(f"获取歌曲列表失败: {str(e)}")
        return []

def download_song(song_detail, album_folders):
    # 提取albumCid（若无则归类到"未知专辑"）
    
    song_name = sanitize_filename(song_detail["name"])
    album_cid = sanitize_filename(song_detail["albumCid"])
    # 动态创建专辑文件夹（仅当该albumCid首次出现时）
    if album_cid not in album_folders:
        album_folders[album_cid] = {
            "folder": song_name,  # 用当前歌曲名命名文件夹
            "created": False      # 标记文件夹尚未创建
        }
    
    # 获取当前专辑的文件夹名
    album_folder_name = album_folders[album_cid]["folder"]
    album_dir = os.path.join("monster_siren_music", album_folder_name)
    
    # 创建文件夹（若未创建）
    if not album_folders[album_cid]["created"]:
        os.makedirs(album_dir, exist_ok=True)
        album_folders[album_cid]["created"] = True
        print(f"📁 创建专辑文件夹: {album_folder_name}")
    
    # 创建专辑文件夹（若未创建）
    album_dir = os.path.join("monster_siren_music", album_folders[album_cid]["folder"])
    if not album_folders[album_cid]["created"]:
        os.makedirs(album_dir, exist_ok=True)
        album_folders[album_cid]["created"] = True
        print(f"📁 创建专辑文件夹: {album_folders[album_cid]['folder']}")
    
    # 生成文件名（歌曲名 + 歌曲ID防重）_{cid_suffix}cid_suffix = song_detail["cid"][:6]
    filename = f"{song_name}.mp3"
    filepath = os.path.join(album_dir, filename)
    
    # 获取下载链接
    song_api = f"https://monster-siren.hypergryph.com/api/song/{song_detail['cid']}"
    try:
        detail_res = requests.get(song_api, headers=headers, timeout=20)
        detail_res.raise_for_status()
        download_url = detail_res.json()["data"]["sourceUrl"]
    except Exception as e:
        print(f"⚠️ 解析下载链接失败: {str(e)}")
        return False
    
    # 下载文件
    try:
        with requests.get(download_url, headers=headers, stream=True, timeout=90) as audio_res:
            audio_res.raise_for_status()
            with open(filepath, 'wb') as f:
                for chunk in audio_res.iter_content(chunk_size=8192):
                    f.write(chunk)
        print(f"✅ 已下载: {album_folders[album_cid]['folder']}/{filename}")
        return True
    except Exception as e:
        print(f"❌ 下载失败: {filename} - {str(e)}")
        return False

if __name__ == "__main__":
    # 全局配置
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Referer': 'https://monster-siren.hypergryph.com/'
    }
    
    # 初始化数据
    songs = fetch_song_list()
    total = len(songs)
    album_folders = defaultdict(dict)  # 使用defaultdict自动处理新专辑[8](@ref)
    
    if not songs:
        print("未获取到歌曲列表，请检查网络或API变更")
        exit()
    
    print(f"共发现{total}首歌曲，开始按专辑分类下载...")
    os.makedirs("monster_siren_music", exist_ok=True)
    
    # 遍历下载
    success_count = 0
    for idx, song in enumerate(songs):
        print(f"\n[{idx+1}/{total}] 处理: {song['name']}")
        if download_song(song, album_folders):
            success_count += 1
        time.sleep(1.5)  # 防请求封禁
    
    # 输出统计
    album_count = len(album_folders)
    print(f"\n下载完成! 成功: {success_count}/{total} | 失败: {total-success_count}")
    print(f"共创建 {album_count} 个专辑文件夹")